﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;

/// <summary>
///类型扩展方法类
/// </summary>
public static class TypeExtensions
{
    /// <summary>
    ///判断指定类型是否为数值类型
    /// </summary>
    /// <param name="type">要检查的类型</param>
    /// <returns>是否是数值类型</returns>
    public static bool IsNumeric(this Type type)
    {
        return type == typeof(Byte)
            || type == typeof(Int16)
            || type == typeof(Int32)
            || type == typeof(Int64)
            || type == typeof(SByte)
            || type == typeof(UInt16)
            || type == typeof(UInt32)
            || type == typeof(UInt64)
            || type == typeof(Decimal)
            || type == typeof(Double)
            || type == typeof(Single);
    }

    /// <summary>
    ///  获取成员元数据的Description特性描述信息
    /// </summary>
    /// <param name="member">成员元数据对象</param>
    /// <param name="inherit">是否搜索成员的继承链以查找描述特性</param>
    /// <returns>返回Description特性描述信息，如不存在则返回成员的名称</returns>
    public static string ToDescription(this MemberInfo member, bool inherit = false)
    {
        DescriptionAttribute desc = member.GetAttribute<DescriptionAttribute>(inherit);
        return desc == null ? null : desc.Description;
    }

    /// <summary>
    /// 检查指定指定类型成员中是否存在指定的Attribute特性
    /// </summary>
    /// <typeparam name="T">要检查的Attribute特性类型</typeparam>
    /// <param name="memberInfo">要检查的类型成员</param>
    /// <param name="inherit">是否从继承中查找</param>
    /// <returns>是否存在</returns>
    public static bool AttributeExists<T>(this MemberInfo memberInfo, bool inherit) where T : Attribute
    {
        return memberInfo.GetCustomAttributes(typeof(T), inherit).Any(m => (m as T) != null);
    }

    /// <summary>
    /// 从类型成员获取指定Attribute特性
    /// </summary>
    /// <typeparam name="T">Attribute特性类型</typeparam>
    /// <param name="memberInfo">类型类型成员</param>
    /// <param name="inherit">是否从继承中查找</param>
    /// <returns>存在返回第一个，不存在返回null</returns>
    public static T GetAttribute<T>(this MemberInfo memberInfo, bool inherit) where T : Attribute
    {
        return memberInfo.GetCustomAttributes(typeof(T), inherit).SingleOrDefault() as T;
    }

    /// <summary>
    /// 从类型成员获取指定Attribute特性
    /// </summary>
    /// <typeparam name="T">Attribute特性类型</typeparam>
    /// <param name="memberInfo">类型类型成员</param>
    /// <param name="inherit">是否从继承中查找</param>
    /// <returns>存在返回第一个，不存在返回null</returns>
    public static T[] GetAttributes<T>(this MemberInfo memberInfo, bool inherit) where T : Attribute
    {
        return memberInfo.GetCustomAttributes(typeof(T), inherit).Cast<T>().ToArray();
    }

    /// <summary>
    /// 判断当前类型的对象能分配于指定泛型类型
    /// </summary>
    /// <param name="givenType">给定类型</param>
    /// <param name="genericType">泛型类型</param>
    /// <returns></returns>
    public static bool IsAssignableToGenericType(this Type givenType, Type genericType)
    {
        if (!genericType.IsGenericType)
        {
            return false;
        }
        var interfaceTypes = givenType.GetInterfaces();
        if (interfaceTypes.Any(interfaceType => interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == genericType))
        {
            return true;
        }
        if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
        {
            return true;
        }
        Type baseType = givenType.BaseType;
        if (baseType == null)
        {
            return false;
        }
        return IsAssignableToGenericType(baseType, genericType);
    }

    /// <summary>
    /// 扩展方法，获得枚举的Description
    /// </summary>
    /// <param name="value">枚举值</param>
    /// <param name="nameInstead">当枚举值没有定义DescriptionAttribute，是否使用枚举名代替，默认是使用</param>
    /// <returns>枚举的Description</returns>
    public static string GetDescription(this Enum value, Boolean nameInstead = true)
    {
        Type type = value.GetType();
        string name = Enum.GetName(type, value);
        if (name == null)
        {
            return null;
        }

        FieldInfo field = type.GetField(name);
        DescriptionAttribute attribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;

        if (attribute == null && nameInstead == true)
        {
            return name;
        }
        return attribute == null ? null : attribute.Description;
    }

    /// <summary>
    /// 根据Description获取枚举
    /// </summary>
    /// <typeparam name="T">枚举类型</typeparam>
    /// <param name="description">枚举描述</param>
    /// <returns>枚举</returns>
    public static T GetEnumName<T>(this string description)
    {
        Type _type = typeof(T);
        foreach (FieldInfo field in _type.GetFields())
        {
            DescriptionAttribute[] _curDesc = field.GetDescriptAttr();
            if (_curDesc != null && _curDesc.Length > 0)
            {
                if (_curDesc[0].Description == description)
                    return (T)field.GetValue(null);
            }
            else
            {
                if (field.Name == description)
                    return (T)field.GetValue(null);
            }
        }
        throw new ArgumentException(string.Format("{0} 未能找到对应的枚举.", description), "Description");
    }
    /// <summary>
    /// 获取字段Description
    /// </summary>
    /// <param name="fieldInfo">FieldInfo</param>
    /// <returns>DescriptionAttribute[] </returns>
    public static DescriptionAttribute[] GetDescriptAttr(this FieldInfo fieldInfo)
    {
        if (fieldInfo != null)
        {
            return (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
        }
        return null;
    }

    /// <summary>
    /// 获取枚举的描述信息
    /// </summary>
    /// <param name="enumValue">枚举值</param>
    /// <returns>描述</returns>
    public static string GetDescription(this Enum enumValue)
    {
        string value = enumValue.ToString();
        FieldInfo field = enumValue.GetType().GetField(value);
        object[] objs = field.GetCustomAttributes(typeof(System.ComponentModel.DescriptionAttribute), false);
        if (objs == null || objs.Length == 0) return value;
        System.ComponentModel.DescriptionAttribute attr = (System.ComponentModel.DescriptionAttribute)objs[0];
        return attr.Description;
    }

    /// <summary>
    /// 获取枚举的描述信息
    /// </summary>
    /// <param name="enumInt">枚举值</param>
    /// <returns>描述</returns>
    public static string GetDescription<T>(this int enumInt)
    {
        try
        {
            T enumValue = (T)Enum.ToObject(typeof(T), enumInt);
            string value = enumValue.ToString();
            FieldInfo field = enumValue.GetType().GetField(value);
            object[] objs = field.GetCustomAttributes(typeof(System.ComponentModel.DescriptionAttribute), false);
            if (objs == null || objs.Length == 0) return value;
            System.ComponentModel.DescriptionAttribute attr = (System.ComponentModel.DescriptionAttribute)objs[0];
            return attr.Description;
        }
        catch
        {
            return string.Empty;
        }
    }

    /// <summary>  
    /// 根据枚举类型得到其所有的 键 与 枚举定义Description属性 的集合  
    /// </summary>  
    /// <param name="enumType"></param>  
    /// <returns></returns>  
    public static Dictionary<string, string> GetEnumNameValues(this Type enumType)
    {
        Dictionary<string, string> nvc = new Dictionary<string, string>();
        Type typeDescription = typeof(DescriptionAttribute);
        System.Reflection.FieldInfo[] fields = enumType.GetFields();
        string strText = string.Empty;
        string strValue = string.Empty;
        foreach (FieldInfo field in fields)
        {
            if (field.FieldType.IsEnum)
            {
                strValue = field.Name;
                object[] arr = field.GetCustomAttributes(typeDescription, true);
                if (arr.Length > 0)
                {
                    DescriptionAttribute aa = (DescriptionAttribute)arr[0];
                    strText = aa.Description;
                }
                else
                {
                    strText = "";
                }
                nvc.Add(strValue, strText);
            }
        }
        return nvc;
    }
    /// <summary>  
    /// 根据枚举类型得到其所有的 键 与 枚举定义Description属性 的集合  
    /// </summary>  
    /// <param name="enumType"></param>  
    /// <returns></returns>  
    public static Dictionary<int, string> GetEnumKeyValues(this Type enumType)
    {
        Dictionary<int, string> nvc = new Dictionary<int, string>();
        Type typeDescription = typeof(DescriptionAttribute);
        System.Reflection.FieldInfo[] fields = enumType.GetFields();
        string strText = string.Empty;
        foreach (FieldInfo field in fields)
        {
            if (field.FieldType.IsEnum)
            {
                var strValue = (int)enumType.InvokeMember(field.Name, BindingFlags.GetField, null, null, null);
                object[] arr = field.GetCustomAttributes(typeDescription, true);
                if (arr.Length > 0)
                {
                    DescriptionAttribute aa = (DescriptionAttribute)arr[0];
                    strText = aa.Description;
                }
                else
                {
                    strText = "";
                }
                nvc.Add(strValue, strText);
            }
        }
        return nvc;
    }

    /// <summary>
    /// 获取时间戳
    /// </summary>
    /// <param name="time"></param>
    /// <returns></returns>
    public static long ToTimeStamp(this DateTime time)
    {
        System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1, 0, 0, 0, 0));
        long t = time.Ticks - startTime.Ticks;
        return t;
    }

    public static DateTime ToTime(this long timeStamp)
    {
        DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
        TimeSpan toNow = new TimeSpan(timeStamp);
        return dtStart.Add(toNow);
    }
}
